/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.control;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.zhiqim.kernel.Z;
import org.zhiqim.kernel.config.Group;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Randoms;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Threads;

/**
 * 线程池控制器，指定池最小值、最大值、初始值，允许线程空闲时长和允许缓存事件大小<br><br>
 * 1.创建时创建初始值大小的线程池，创建事件队列，和主线程<br>
 * 2.其他线程通过post传递事件可执行事件<br>
 * 3.主线程调度线程池处理事件，并检查线程池空闲线程
 *
 * @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
 */
public class ThreaderController extends ThreadServicer
{
    private static final Log log = LogFactory.getLog(ThreaderController.class);
    
    private volatile int poMinSize;                         //线程池最小数目
    private volatile int poMaxSize;                         //线程池最大数目
    private volatile int poIdleTimeMs;                      //线程池线程空闲时长(毫秒)
    private volatile int poQueueSize;                       //线程池队列大小
    private volatile int threadTimeoutMs;                   //线程池线程等待超时时长(毫秒)，默认5*1000
    
    private ThreadGroup threadGroup;                          //指定线程组
    private String threadName;                                //指定线程名
    private boolean isLogger;                                //是否打印繁忙日志
    
    private final LinkedList<Threader> theaderList;          //所有线程列表
    private final Queue<Runnable> queue;                     //等待处理的可执行事件
    private final AtomicInteger activeSize;                  //活跃线程数
    
    public ThreaderController()
    {
        threadTimeoutMs = 5 * 1000;
        threadName = "Threader-" + Randoms.upperLetters(1)+Randoms.lowerLettersDigits(3);
        
        theaderList = new LinkedList<>();
        queue = new Queue<Runnable>();
        activeSize = new AtomicInteger();
    }
    
    @Override /** 不再支持子类重写，创建后不能修改 */
    protected final ThreadGroup getThreadGroup()
    {
        return threadGroup;
    }
    
    @Override /** 不再支持子类重写，修改请通过setThreadName设置 */
    protected final String getThreadName()
    {
        return "Controller-" + threadName;
    }
    
    /*********************************************************************************************/
    //参数设置
    /*********************************************************************************************/
    
    /**
     * 设置线程池中线程等待超时时长
     * 
     * @param threadTimeoutMs   超时时长，单位毫秒
     */
    public void setThreadTimeoutMs(int threadTimeoutMs)
    {
        this.threadTimeoutMs = threadTimeoutMs;
    }
    
    /**
     * 设置线程池中线程名，创建前设置，创建后修改无效，控制线程名为Controller-${threadName}
     * 
     * @param threadName    线程名
     */
    public void setThreadName(String threadName)
    {
        Asserts.as(!isRunning()?null:"线程池创建后不支持修改");
        this.threadName = threadName;
    }
    
    /**
     * 设置线程池在繁忙时是否打印日志，未设置默认是打印
     * 
     * @param isLogger      是否打印日志
     */
    public void setLogger(boolean isLogger)
    {
        this.isLogger = isLogger;
    }
    
    /**
     * 设置线程池必须的四个参数，支持创建后重新设置
     * 
     * @param poMinSize     线程池最小值
     * @param poMaxSize     线程池最大值
     * @param poIdleTime    线程池线程空闲时长，单位秒
     * @param poQueueSize   线程池允许缓存事件大小
     */
    public ThreaderController set(int poMinSize, int poMaxSize, int poIdleTime, int poQueueSize)
    {
        this.poMinSize = (poMinSize < 1)?1:poMinSize;
        this.poMaxSize = (poMaxSize < poMinSize)?poMinSize:poMaxSize;
        this.poIdleTimeMs = ((poIdleTime < 60)?60:poIdleTime) * 1000;
        this.poQueueSize = poQueueSize<(this.poMaxSize*3)?(this.poMaxSize*3):poQueueSize;
        
        return this;
    }
    
    /*********************************************************************************************/
    //创建&销毁
    /*********************************************************************************************/
    
    @Override
    public boolean openBefore()
    {
        //1.检查是否有设置ID，如在zhiqim.xml配置服务，或通过setId函数指定值的
        if (id != null)
        {
            //1.1有设置ID的，线程名为ID首字母大写
            threadName = Strings.toUpperFirstChar(id);
            
            Group grp = Z.conf().group(id);
            if (grp != null)
            {//1.2 读配置参数，如果没有配置的set方法会取默认值
                set(grp.getInt("poMinSize"), grp.getInt("poMaxSize"), grp.getInt("poIdleTime"), grp.getInt("poQueueSize"));
            }
        }
        
        //2.判断线程池参数是否正确
        Asserts.as((poMaxSize >= poMinSize && poMinSize > 0 && poIdleTimeMs > 0 && poQueueSize > 0)?null:"线程池服务配置参数不正确");
        
        //3.初始化创建线程操作者
        this.threadGroup = new ThreadGroup(threadName);
        for (int i=0;i<poMinSize;i++)
        {
            openThreader();
        }
        
        return true;
    }
    
    @Override
    public void closeAfter()
    {
        closeThreaders();
        log.info("线程池[%s]监视线程退出", threadName);
    }
    
    @Override
    public void loop()
    {
        if (theaderList.size() > poMinSize)
        {//如果线程池中线程比最小值大，则检查线程池是否有空闲线程，有则关闭
            chkThreaders();
        }
        
        //当前线程池数据
        log.info("线程池[name:%s,min:%d,max:%d,cur:%d,active:%d,queue:%d,idleTime:%d]", threadName, poMinSize, poMaxSize, theaderList.size(), activeSize.get(), queue.size(), poIdleTimeMs / 1000);
        
        //等待下次检查
        Threads.sleepIgnoreException(poIdleTimeMs);
    }
    
    /*********************************************************************************************/
    //线程池管理
    /*********************************************************************************************/
    
    /** 开启一个新的线程 */
    private void openThreader()
    {
        Threader threader = new Threader(this);
        threader.open();
        synchronized (theaderList)
        {
            theaderList.add(threader);
        }
    }
    
    /** 关闭所有线程 */
    private void closeThreaders()
    {
        synchronized (theaderList)
        {
            for (Threader threader : theaderList)
            {
                threader.close();
                threader = null;
            }
            theaderList.clear();
        }
    }
    
    /** 检查线程池 */
    private void chkThreaders()
    {
        //1.找出需要关闭的线程列表
        List<Threader> list = new ArrayList<>();
        synchronized (theaderList)
        {
            for (Iterator<Threader> it=theaderList.iterator();it.hasNext();)
            {
                if (theaderList.size() - list.size() <= poMinSize)
                    break;
                
                Threader threader = it.next();
                if (threader.isIdleTimeout(poIdleTimeMs))
                {//空闲超时的加入到需要关闭列表
                    list.add(threader);
                }
            }
        }
        
        //2.执行关闭操作
        for (Threader threader : list)
        {
            if (threader.isIdleTimeout(poIdleTimeMs))
            {//再作一次空闲超时判断
                synchronized (theaderList)
                {
                    theaderList.remove(threader);
                }
                
                threader.close();
            }
        }
        
        //3.清理列表
        list.clear();list = null;
    }
    
    /*********************************************************************************************/
    //线程池处理，处理事件&清理事件&判断事件是否存在
    /*********************************************************************************************/
    
    public boolean execute(Runnable command)
    {
        return execute(command, false);
    }
    
    public synchronized boolean execute(Runnable command, boolean priority)
    {
        if (!isRunning() || command == null)
            return false;
        
        int threaderSize = theaderList.size();
        int activeSize = getThreaderActiveSize();
        if (activeSize < threaderSize)
        {//线程池空闲
            queue.post(command, priority);
            return true;
        }
        
        if (queue.size() < threaderSize)
        {//线程池忙，缓冲一个线程数批次
            queue.post(command, priority);
            return true;
        }
        
        if (threaderSize < poMaxSize)
        {//线程池较忙，增加线程数至最大
            openThreader();
            queue.post(command, priority);
            return true;
        }
        
        if (queue.size() < poQueueSize)
        {//线程池繁忙，接近最大处理能力
            queue.post(command, priority);
            return true;
        }
        
        if (isLogger)
        {//线程池繁忙超限时打印日志
            log.fatal("线程池[%s]繁忙超限，事件对队已满，无法接收处理", threadName);
        }
        return false;
    }
    
    /*********************************************************************************************/
    //线程操作者调用，接受一个事件&完成事件设置数目
    /*********************************************************************************************/
    
    Runnable accept()
    {
        return queue.accept(threadTimeoutMs);
    }
    
    void active()
    {
        activeSize.getAndIncrement();
    }
    
    void idle()
    {
        activeSize.getAndDecrement();
    }
    
    /*********************************************************************************************/
    //线程池中对列信息&操作
    /*********************************************************************************************/
    
    public void clear()
    {
        queue.clear();
    }
    
    public boolean contains(Runnable command)
    {
        return queue.contains(command);
    }
    
    public int size()
    {
        return queue.size();
    }
    
    public boolean isEmpty()
    {
        return queue.isEmpty();
    }
    
    public Queue<Runnable> getQueue()
    {
        return queue;
    }
    
    /*********************************************************************************************/
    //获取线程池运行时参数
    /*********************************************************************************************/
    
    public List<Threader> getThreaderList()
    {
        return Collections.unmodifiableList(theaderList);
    }
    
    public int getThreaderSize()
    {
        return theaderList.size();
    }

    public int getThreaderActiveSize()
    {
        return activeSize.get();
    }
    
    public int getThreaderIdleSize()
    {
        return theaderList.size() - activeSize.get();
    }
    
    /*********************************************************************************************/
    //获取线程池配置参数
    /*********************************************************************************************/
    
    public int getPoMinSize()
    {
        return poMinSize;
    }

    public int getPoMaxSize()
    {
        return poMaxSize;
    }
    
    public int getPoIdleTime()
    {
        return poIdleTimeMs / 1000;
    }
    
    public int getPoQueueSize()
    {
        return poQueueSize;
    }
}
